BFS 典型的迷宫问题
这个是BFS搜索的典型问题,好好整理一下:
给定一个迷宫,入口为左上角,出口为右下角,问是否有路径从入口到出口,若有则输出一条这样的路径。注意移动可以从上、下、左、右、上左、上右、下左、下右八个方向进行。迷宫输入0表示可走,输入1表示墙。易得可以用1将迷宫围起来避免边界问题。本题采用BFS算法给出解。注意,利用BFS算法给出的路径必然是一条最短路径。
input:
1
6 8
0 1 1 1 0 1 1 1
1 0 1 0 1 0 1 0
0 1 0 0 1 1 1 1
0 1 1 1 0 0 1 1
1 0 0 1 1 0 0 0
0 1 1 0 0 1 1 0
output:
YES
(1,1) (2,2) (3,3) (3,4) (4,5) (4,6) (5,7) (6,8)
基本思路:
采用BFS的思路,每个位置相当于一个结点,用BFS进行广度搜索,相当于往外一环一环扩散的感觉,最后看能否达到出口的位置。
实现以及技巧:
1.基本的数据结构:相比对于一棵树的BFS来说,这里的BFS中的Node是一个坐标,因此要自定义好结点,typedef struct Node{int x; int y;}Node;BFS里面要用到队列,对基本的队列的库函数的声明和使用要熟悉,Q.size() Q.push(Node) Q.front() 以及Q.pop()
2.关于path的问题:由于要存储路径信息,这里的path是一个二维的指针数组,注意这种声明以及初始化的方式:声明Node **path;初始化:
path=new Node*[MAXL];
for(i=0;i<=MAXL;i++)
{path[i]=new Node[MAXH];}
应该还有其他的表述方式,总之要会用一个,这里涉及到二维时候的指针还是挺麻烦的。
3.还要注意每次path的更新点的选择问题,在每次元素入队的时候,比如当前元素为now,检查它周围的8个点,让没有墙的点入队,比如一个没有墙的点是temp就在这个位置上更新,path[temp.x][temp.y]=now。
4.path输出的问题也很重要,这个最好就记下来,就是递归输出,比较典型,具体看代码的outputpath函数。
5.考虑向周围移动的时候:向周围的8个点移动的时候可以先设置好一个二维数组:
Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};
之后一个循环,把对应的x y值加上去就好,这样比较省事。注意结构体赋初值的时候也可以用这种小括号的形式:Node start={1,1};
6.还有一点容易忽略,想周围移动的时候,已经探测过的点要做个标记,比如标记成-1或者类似的,这样就不会绕回去了,否则有可能形成一个环。
7.还有其他的技巧,就是在地图初始化的时候,在周围加上一圈的围墙,这样在具体BFS的时候就不用再考虑边界的问题了。
具体代码如下:
//http://blog.csdn.net/that163/article/details/8069764 #include<iostream> #include<cstdio> #include<queue> #include<cstring> #define MAXH 20 #define MAXL 20 using namespace std; typedef struct Node{ int x; int y; }Node; //记录地图信息 int maze[MAXH][MAXL]; //记录路径信息 //Node*path[MAXH][MAXL]; Node **path; Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}}; bool BFS(Node start,Node end) { int i; Node tempN; Node tempNM; queue<Node>Q; Q.push(start); maze[start.x][start.y]=-1; //while(tempN.x!=end.x&&tempN.y!=end.y&&Q.size!=0) while(Q.size()!=0) { tempN=Q.front(); Q.pop(); //遍历8个方向全部的点 for(i=0;i<8;i++) { tempNM.x=tempN.x+move[i].x; tempNM.y=tempN.y+move[i].y; //若是移动之后的点 位置是0 表示可以通过 if(tempNM.x>=1&&tempNM.y>=1&&tempNM.x<=end.x&&tempNM.y<=end.y&&maze[tempNM.x][tempNM.y]==0) { //孩子结点入队 Q.push(tempNM); //已经尝试过的点标记成-1 maze[tempNM.x][tempNM.y]=-1; path[tempNM.x][tempNM.y]=tempN; } } } if(tempN.x==end.x&&tempN.y==end.y) {return true;} else {return false;} } void outputpath(Node end) { //可以递归输出 Node temp=end; if(end.x==1&&end.y==1) { printf("(%d,%d)",end.x,end.y); return; } else { //取出指针的内容 temp=path[temp.x][temp.y]; outputpath(temp); if(temp.x!=1&&temp.y!=1) {printf("(%d,%d)",temp.x,temp.y);} } return; } int main() { freopen("in.txt","r",stdin); int hang,lie,N; int i,j; scanf("%d",&N); while(N--) { //输入部分 scanf("%d%d",&hang,&lie); for(i=1;i<=hang;i++) { for(j=1;j<=lie;j++) { if(j==lie) { scanf(" %d",&maze[i][j]); } else { scanf("%d",&maze[i][j]); } } } Node start={1,1}; //注意结构体的这种用中括号来赋值的方式 Node end={hang,lie}; //二维指针数组的规定初始值的方式 //此时path是一个指向一维指针数组的指针 path=new Node*[MAXL]; for(i=0;i<=MAXL;i++) {path[i]=new Node[MAXH];} //调用BFS函数进行搜索 更新path矩阵信息 bool connect=BFS(start,end); if(connect) puts("YES"); else puts("NO"); //输出路径信息 outputpath(end); printf("(%d,%d)\n",6,8); } return 0; }